package MathTextModeler
{
	import MyDisplayObjects.DraggableMC;
	
	import avmplus.getQualifiedClassName;
	
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;

	/** An object of this class provides visuals for the closed containers within the diagram.
	 */ 
	public class DiagramContainer extends Sprite
	{
		private var WIDTH:Number, HEIGHT:Number;
		private var placeInCenter:Boolean;
		private var shapeType:String, expandDirection:String;
		private var enabledColor:uint, enabledStrokeColor:uint, disabledColor:uint, disabledStrokeColor:uint, highlightedColor:uint, highlightedStrokeColor:uint, selectedColor:uint, selectedStrokeColor:uint, expandStrokeColor:uint;
		private var enabledAlpha:Number, enabledStrokeAlpha:Number, disabledAlpha:Number, disabledStrokeAlpha:Number, highlightedAlpha:Number, highlightedStrokeAlpha:Number, selectedAlpha:Number, selectedStrokeAlpha:Number, expandStrokeAlpha:Number;
		private var enabledStrokeSize:Number, disabledStrokeSize:Number, highlightedStrokeSize:Number, selectedStrokeSize:Number, expandStrokeSize:Number;
		private var highlightIfDisabled:Boolean, selectIfDisabled:Boolean;
		private var otherMCs:Array = null; // all other objects, containers, etc.
		private var unitMCs:Array = null; // the unit objects (e.g., marbles)
		private var variableMCs:Array = null; // the variable
		public var position:Point;
		
		private var _enabled:Boolean = true, _highlighted:Boolean=false, _selected:Boolean=false, _mouseOver:Boolean = false, _used:Boolean = false;
		public function get used():Boolean{if (otherMCs.length > 0 || unitMCs.length > 0 || variableMCs.length > 0){return true} else {return false;}}
		public function get enabled():Boolean{return _enabled;}
		public function set enable(b:Boolean):void{_enabled = b; redraw();}
		public function get highlighted():Boolean{return _highlighted;}
		public function set highlight(b:Boolean):void{if (b && (_enabled || highlightIfDisabled)){_highlighted = true;} else {_highlighted = false;} redraw();}
		public function get selected():Boolean{return _selected;}
		public function set select(b:Boolean):void{if (b && (_enabled || selectIfDisabled)){_selected = true;} else {_selected = false;} redraw();}
		
		/**
		 * @width, @height - the initial width and height of this display
		 * @shapeType - "rect", "ellipse", "roundRect", "circle"
		 * @expandDirection - "up", "down", "left", "right", "center" - center expands this object evenly, "none" - no expansion
		 */ 
		public function DiagramContainer(width:Number, height:Number, placeInCenter:Boolean, shapeType:String, expandDirection:String, enabledColor:uint=0xFFFFFF, enabledAlpha:Number=1, enabledStrokeSize:Number=1, enabledStrokeColor:uint=0x000000, enabledStrokeAlpha:Number=1, disabledColor:uint=0xFFFFFF, disabledAlpha:Number=1, disabledStrokeSize:Number=1, disabledStrokeColor:uint=0x000000, disabledStrokeAlpha:Number=1, highlightedColor:uint=0xFFFFFF, highlightedAlpha:Number=1, highlightedStrokeSize:Number=1, highlightedStrokeColor:uint=0x000000, highlightedStrokeAlpha:Number=1, selectedColor:uint=0xFFFFFF, selectedAlpha:Number=1, selectedStrokeSize:Number=1, selectedStrokeColor:uint=0x000000, selectedStrokeAlpha:Number=1, highlightIfDisabled:Boolean = false, selectIfDisabled:Boolean = false, expandStrokeSize:Number=1, expandStrokeColor:uint=0x000000, expandStrokeAlpha:Number=1)
		{
			initialize(width, height, placeInCenter, shapeType, expandDirection, enabledColor, enabledAlpha, enabledStrokeSize, enabledStrokeColor, enabledStrokeAlpha, disabledColor, disabledAlpha, disabledStrokeSize, disabledStrokeColor, disabledStrokeAlpha, highlightedColor, highlightedAlpha, highlightedStrokeSize, highlightedStrokeColor, highlightedStrokeAlpha, selectedColor, selectedAlpha, selectedStrokeSize, selectedStrokeColor, selectedStrokeAlpha, highlightIfDisabled, selectIfDisabled, expandStrokeSize, expandStrokeColor, expandStrokeAlpha);
			this.position = new Point(0, 0);
			otherMCs = new Array();
			unitMCs = new Array();
			variableMCs = new Array();
		}
		public function initialize(width:Number, height:Number, placeInCenter:Boolean, shapeType:String, expandDirection:String, enabledColor:uint=0xFFFFFF, enabledAlpha:Number=1, enabledStrokeSize:Number=1, enabledStrokeColor:uint=0x000000, enabledStrokeAlpha:Number=1, disabledColor:uint=0xFFFFFF, disabledAlpha:Number=1, disabledStrokeSize:Number=1, disabledStrokeColor:uint=0x000000, disabledStrokeAlpha:Number=1, highlightedColor:uint=0xFFFFFF, highlightedAlpha:Number=1, highlightedStrokeSize:Number=1, highlightedStrokeColor:uint=0x000000, highlightedStrokeAlpha:Number=1, selectedColor:uint=0xFFFFFF, selectedAlpha:Number=1, selectedStrokeSize:Number=1, selectedStrokeColor:uint=0x000000, selectedStrokeAlpha:Number=1, highlightIfDisabled:Boolean = false, selectIfDisabled:Boolean = false, expandStrokeSize:Number=1, expandStrokeColor:uint=0x000000, expandStrokeAlpha:Number=1):void{
			this.WIDTH = width; this.HEIGHT = height;
			this.placeInCenter = placeInCenter;
			this.shapeType = shapeType;
			this.expandDirection = expandDirection;
			this.enabledColor = enabledColor
			this.enabledStrokeColor = enabledStrokeColor;
			this.disabledColor = disabledColor;
			this.disabledStrokeColor = disabledStrokeColor;
			this.highlightedColor = highlightedColor;
			this.highlightedStrokeColor = highlightedStrokeColor;
			this.selectedColor = selectedColor;
			this.selectedStrokeColor = selectedStrokeColor;
			this.enabledAlpha = enabledAlpha;
			this.enabledStrokeAlpha = enabledStrokeAlpha;
			this.disabledAlpha = disabledAlpha;
			this.disabledStrokeAlpha = disabledStrokeAlpha;
			this.highlightedAlpha = highlightedAlpha;
			this.highlightedStrokeAlpha = highlightedStrokeAlpha;
			this.selectedAlpha = selectedAlpha;
			this.selectedStrokeAlpha = selectedStrokeAlpha;
			this.enabledStrokeSize = enabledStrokeSize;
			this.disabledStrokeSize = disabledStrokeSize;
			this.highlightedStrokeSize = highlightedStrokeSize;
			this.highlightIfDisabled = highlightIfDisabled;
			this.selectedStrokeSize = selectedStrokeSize;
			this.selectIfDisabled = selectIfDisabled;
			this.expandStrokeSize = expandStrokeSize;
			this.expandStrokeColor = expandStrokeColor;
			this.expandStrokeAlpha = expandStrokeAlpha;
			redraw();
		}
		
		/** Places a clickable image at an open space in the container */
		public function placeDraggable (dmc:DraggableMC):void{
			if (this.placeInCenter){
				var c:Point = new Point(this.x + (this.width - 0*dmc.width)/2, this.y + (this.height - 0*dmc.height)/2);
				var p:Point;
				if (dmc.type == "unit"){
					p = moveSquareFromPoint(c, dmc.width, dmc.height, this.unitMCs.length, 1.25, 1, -1, -1)
					dmc.x = p.x;
					dmc.y = p.y;
					this.unitMCs.push(dmc);
				} else if (dmc.type == "variable"){
					dmc.x = this.x + (this.width - dmc.width)/2;
					dmc.y = this.y + (this.height - dmc.height)/2;
					this.variableMCs.push(dmc);
				} else {
					dmc.x = this.x + (this.width - dmc.width)/2;
					dmc.y = this.y + (this.height - dmc.height)/2;
					this.otherMCs.push(dmc);
				}
			} else {
				if (dmc.type == "unit"){
					dmc.x = this.x + (this.unitMCs.length % Math.floor(this.width/(dmc.width+20))) * (dmc.width+20)+10;
					dmc.y = this.y + Math.floor(this.unitMCs.length / Math.floor(this.width/(dmc.width+20))) * (dmc.height+20)+10;
					this.unitMCs.push(dmc);
				} else if (dmc.type == "variable"){
					dmc.x = this.x + (this.width - dmc.width)/2;
					dmc.y = this.y + (this.height - dmc.height)/2;
					this.variableMCs.push(dmc);
				} else {
					dmc.x = this.x + (this.width - dmc.width)/2;
					dmc.y = this.y + (this.height - dmc.height)/2;
					this.otherMCs.push(dmc);
				}
			}
			dmc.associatedDiagramContainer = this;
		}
		
		/** Checks to see whether the clickable mc is within bounds, if so place it in appropriate arrays */
		public function placeDraggableIfWithinBounds (dmc:DraggableMC):Boolean{
			if (this.hitTestObject(dmc)){
				if (dmc.associatedDiagramContainer != this){
					if (dmc.type == "unit"){
						if (dmc.associatedDiagramContainer != null)	DiagramContainer(dmc.associatedDiagramContainer).removeUnitMC(dmc);
						this.unitMCs.push(dmc);
					} else if (dmc.type == "variable"){
						if (dmc.associatedDiagramContainer != null)	DiagramContainer(dmc.associatedDiagramContainer).removeVariableMC(dmc);
						this.variableMCs.push(dmc);
					} else {
						if (dmc.associatedDiagramContainer != null)	DiagramContainer(dmc.associatedDiagramContainer).removeOtherMC(dmc);
						this.otherMCs.push(dmc);
					}
					dmc.associatedDiagramContainer = this;
				}				
				return true;
			} else {
				return false;
			}
		}
		
		/** Removes everything */
		public function removeAll():void
		{
			var dmc:DraggableMC;
			for (var i:int=unitMCs.length-1; i >= 0; i--)
			{
				unitMCs.splice(i, 1);
			}
			for (i=variableMCs.length-1; i >= 0; i--)
			{
				variableMCs.splice(i, 1);
			}
			for (i=otherMCs.length-1; i >= 0; i--)
			{
				otherMCs.splice(i, 1);
			}
		}
		
		/** Removes both a unit and its origin point from arrays */
		public function removeUnitMC (dmc:DraggableMC):Boolean
		{
			for (var i:int=0; i < unitMCs.length; i++)
			{
				if (unitMCs[i] == dmc)
				{
					unitMCs.splice(i, 1);
					return true;
				}
			}
			return false;
		}
		
		/** Removes both a variable and its origin point from arrays */
		public function removeVariableMC (dmc:DraggableMC):Boolean
		{
			for (var i:int=0; i < variableMCs.length; i++)
			{
				if (variableMCs[i] == dmc)
				{
					variableMCs.splice(i, 1);
					return true;
				}
			}
			return false;
		}
		/** Removes both another object and its origin point from arrays */
		public function removeOtherMC (dmc:DraggableMC):Boolean
		{
			for (var i:int=0; i < otherMCs.length; i++)
			{
				if (otherMCs[i] == dmc)
				{
					otherMCs.splice(i, 1);
					return true;
				}
			}
			return false
		}
		
		
		/////////////////////////////////// DRAW          ///////////////////////////////////////////
		public function adjustForLocationChange ():void{
			// get relative position to diagram, and move
			var unitMCs:Array = this.unitMCs.slice();
			this.unitMCs = new Array();
			for (var i:int=0; i < unitMCs.length; i++){
				this.placeDraggable(unitMCs[i]);
				this.unitMCs[i].origin = new Point (unitMCs[i].x, unitMCs[i].y);
			}
			var variableMCs:Array = this.variableMCs.slice();
			this.variableMCs = new Array();
			for (i=0; i < variableMCs.length; i++){
				this.placeDraggable(variableMCs[i]);
				this.variableMCs[i].origin = new Point (variableMCs[i].x, variableMCs[i].y);
			}
			var otherMCs:Array = this.otherMCs.slice();
			this.otherMCs = new Array();
			for (i=0; i < otherMCs.length; i++){
				this.placeDraggable(otherMCs[i]);
				this.otherMCs.origin = new Point (otherMCs[i].x, otherMCs[i].y);
			}
			position = new Point (this.x, this.y);
		}
		
		/** Draw based on current color */
		private function redraw():void
		{
			var color:uint, strokeColor:uint;
			var alpha:Number, strokeAlpha:Number;
			var strokeSize:Number;
			if (highlighted)
			{
				color = highlightedColor; alpha = highlightedAlpha, strokeSize = highlightedStrokeSize; strokeColor = highlightedStrokeColor; strokeAlpha = highlightedStrokeAlpha;
			} else if (selected)
			{
				color = selectedColor; alpha = selectedAlpha, strokeSize = selectedStrokeSize; strokeColor = selectedStrokeColor; strokeAlpha = selectedStrokeAlpha;
			}
			else if (enabled)
			{
				color = enabledColor; alpha = enabledAlpha, strokeSize = enabledStrokeSize; strokeColor = enabledStrokeColor; strokeAlpha = enabledStrokeAlpha;
			} else
			{
				color = disabledColor; alpha = disabledAlpha, strokeSize = disabledStrokeSize; strokeColor = disabledStrokeColor; strokeAlpha = disabledStrokeAlpha;
			}
			this.graphics.clear();
			this.graphics.lineStyle(strokeSize, strokeColor, strokeAlpha);
			this.graphics.beginFill(color, alpha);
			if (shapeType.toLowerCase() == "rect" || shapeType.toLowerCase() == "rectangle"){
				if (expandDirection.toLowerCase()=="left"){
					this.graphics.moveTo(WIDTH,HEIGHT); this.graphics.lineTo(0, HEIGHT); this.graphics.lineTo(0,0); this.graphics.lineTo(WIDTH,0); 
					this.graphics.lineStyle(expandStrokeSize, expandStrokeColor, expandStrokeAlpha);
					this.graphics.lineTo(WIDTH,HEIGHT);
				} else if (expandDirection.toLowerCase()=="right"){
					this.graphics.moveTo(0,0); this.graphics.lineTo(WIDTH, 0); this.graphics.lineTo(WIDTH,HEIGHT); this.graphics.lineTo(0, HEIGHT);
					this.graphics.lineStyle(expandStrokeSize, expandStrokeColor, expandStrokeAlpha);
					this.graphics.lineTo(0, 0);
				} else if (expandDirection.toLowerCase()=="top"){
					this.graphics.moveTo(0, HEIGHT); this.graphics.lineTo(0,0); this.graphics.lineTo(WIDTH, 0); this.graphics.lineTo(WIDTH,HEIGHT); 
					this.graphics.lineStyle(expandStrokeSize, expandStrokeColor, expandStrokeAlpha);
					this.graphics.lineTo(0, HEIGHT);
				} else if (expandDirection.toLowerCase()=="bottom"){
					this.graphics.moveTo(WIDTH, 0); this.graphics.lineTo(WIDTH,HEIGHT); this.graphics.lineTo(0, HEIGHT); this.graphics.lineTo(0,0); 
					this.graphics.lineStyle(expandStrokeSize, expandStrokeColor, expandStrokeAlpha);
					this.graphics.lineTo(WIDTH, 0);
				} else{
					this.graphics.drawRect(0, 0, WIDTH, HEIGHT);
				}							
			} else if (shapeType.toLowerCase() == "ellipse"){
				this.graphics.drawEllipse(0, 0, WIDTH, HEIGHT);
			} else if (shapeType.toLowerCase() == "roundRect"){
				this.graphics.drawRoundRect(0, 0, WIDTH, HEIGHT, Math.min(WIDTH/10, HEIGHT/10), Math.min(WIDTH/10, HEIGHT/10));
			} else {
				this.graphics.drawRect(0, 0, WIDTH, HEIGHT);
			}
			this.graphics.endFill();	
		}
		
		/** Will move to a place in a square with the following cardinality, 1, 9, 25, 49.
		 * 0 is center, 1 is top-left of first square (ring), moves clockwise, at 25 moves to next ring.
		 */
		private static function moveSquareFromPoint(point:Point, width:Number, height:Number, index:uint, distanceMultiplier:Number=1.2, scale:Number=1, offsetX:Number=-1, offsetY:Number=-1):Point
		{
			var x:Number, y:Number;
			//trace(this.width, this.height, point, index, distanceMultiplier, scale);
			if (offsetX < 0 || offsetY < 0)
			{
				offsetX = width * distanceMultiplier * scale;
				offsetY = height * distanceMultiplier * scale;
			}
			x = point.x - width/2;//*scale;
			y = point.y - height/2;//*scale;
			switch (index+1)
			{
				case 1: x +=  0*offsetX; y +=  0*offsetY; break;
				case 2: x += -1*offsetX; y += -1*offsetY; break; 
				case 3: x +=  0*offsetX; y += -1*offsetY; break; 
				case 4: x +=  1*offsetX; y += -1*offsetY; break; 
				case 5: x +=  1*offsetX; y +=  0*offsetY; break; 
				case 6: x +=  1*offsetX; y +=  1*offsetY; break; 
				case 7: x +=  0*offsetX; y +=  1*offsetY; break; 
				case 8: x += -1*offsetX; y +=  1*offsetY; break; 
				case 9: x += -1*offsetX; y +=  0*offsetY; break; 
				case 10: x += -2*offsetX; y += -2*offsetY; break; 
				case 11: x += -1*offsetX; y += -2*offsetY; break; 
				case 12: x +=  0*offsetX; y += -2*offsetY; break; 
				case 13: x +=  1*offsetX; y += -2*offsetY; break; 
				case 14: x +=  2*offsetX; y += -2*offsetY; break; 
				case 15: x +=  2*offsetX; y += -1*offsetY; break; 
				case 16: x +=  2*offsetX; y +=  0*offsetY; break; 
				case 17: x +=  2*offsetX; y +=  1*offsetY; break; 
				case 18: x +=  2*offsetX; y +=  2*offsetY; break; 
				case 19: x +=  1*offsetX; y +=  2*offsetY; break; 
				case 20: x +=  0*offsetX; y +=  2*offsetY; break; 
				case 21: x += -1*offsetX; y +=  2*offsetY; break; 
				case 22: x += -2*offsetX; y +=  2*offsetY; break; 
				case 23: x += -2*offsetX; y +=  1*offsetY; break; 
				case 24: x += -2*offsetX; y +=  0*offsetY; break; 
				case 25: x += -2*offsetX; y += -1*offsetY; break; 
				default: x += offsetX*(4*Math.random() - 2); y += offsetY*(4*Math.random() - 2); trace("Too many objects");break;
				
			} 
			return new Point(x, y);
		}
	}
}